package com.ruoyi.tcp.util;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Objects;

/**
 * @author 蒋翔 SY100242
 * @date 2024/8/3 9:49
 * @email SY100242@hnlens.com
 */
@Slf4j
public class TcpAesUtil {

    // private static final String KEY_ALGORITHM = "AES";
    private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/NoPadding";// 默认的加密算法

    private static final byte[] PROTOCOL_PREFIX = "7E04".getBytes(StandardCharsets.UTF_8);
    private static final byte[] PROTOCOL_SUFFIX = "7E05".getBytes(StandardCharsets.UTF_8);

    /**
     * AES 加密操作
     *
     * @param byteContent 待加密内容
     * @param password    加密密码
     * @return
     */
    public static byte[] encrypt(byte[] byteContent, String password) {
        try {
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器
            int blockSize = cipher.getBlockSize();
            int plaintextLength = byteContent.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(byteContent, 0, plaintext, 0, byteContent.length);
            cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器
            //return cipher.doFinal(plaintext);// 加密
            return cipher.doFinal(plaintext);//
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * AES 解密操作
     *
     * @param content
     * @param password
     * @return
     */
    public static byte[] decrypt(byte[] content, String password) {
        try {
            // 实例化
            Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器
            // 执行操作
            byte[] bytes = cipher.doFinal(content);
            //去除后面的补0的字节
//            return removeTrailingZeroBytes(bytes);
            return bytes;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * 生成加密秘钥
     *
     * @return
     */
    private static SecretKeySpec getSecretKey(final String password) {
        byte[] newpass = alignByte(password);
        System.arraycopy(password.getBytes(), 0, newpass, 0, newpass.length);
        return new SecretKeySpec(newpass, "AES");
    }


    public static byte[] alignByte(String source) {
        byte[] bytes = source.getBytes(StandardCharsets.UTF_8);
        int i = bytes.length % 16;
        if (i == 0) {
            return bytes;
        }
        int newSize = bytes.length + (16 - i);
        byte[] newData = new byte[newSize];
        System.arraycopy(bytes, 0, newData, 0, bytes.length);
        return newData;
    }

    public static byte[] removeTrailingZeroBytes(byte[] data) {
        int i = data.length - 1;
        while (i >= 0 && data[i] == 0) {
            i--;
        }
        return i < 0 ? new byte[0] : Arrays.copyOf(data, i + 1);
    }

    public static String byte2hex(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs.append("0");
            }
            hs.append(stmp);
        }
        return hs.toString().toUpperCase();
    }

    public static byte[] hex2byte(String hex) {
        if (hex.length() % 2 != 0) {
            return null;
        }
        byte[] b = new byte[hex.length() / 2];
        for (int i = 0; i < hex.length() / 2; i++) {
            int high = Integer.parseInt(hex.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hex.substring(i * 2 + 1, i * 2 + 2), 16);
            b[i] = (byte) (high * 16 + low);
        }
        return b;
    }

    public static Long byteArrayToLong(byte[] b) {
        String s = new String(b, StandardCharsets.UTF_8);
        int length = s.length();
        Long sum = 0L;
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            int digit = Character.digit(c, 16);
            if (digit == -1) {
                return sum;
            }
            sum = sum * 16L + digit;
        }
        return sum;
    }

    public static byte[] intToByteArray(int l) {
        return new byte[]{
                (byte) ((l >> 8) & 0xFF),
                (byte) (l & 0xFF)
        };
    }

    public static byte[] longToByteArray12(Long l) {
        return new byte[]{
//                (byte) ((l >> 56) & 0xFF),
//                (byte) ((l >> 48) & 0xFF),
                (byte) ((l >> 40) & 0xFF),
                (byte) ((l >> 32) & 0xFF),
                (byte) ((l >> 24) & 0xFF),
                (byte) ((l >> 16) & 0xFF),
                (byte) ((l >> 8) & 0xFF),
                (byte) (l & 0xFF)
        };
    }

    public static byte[] longToByteArray8(Long l) {
        return new byte[]{
//                (byte) ((l >> 56) & 0xFF),
//                (byte) ((l >> 48) & 0xFF),
//                (byte) ((l >> 40) & 0xFF),
//                (byte) ((l >> 32) & 0xFF),
                (byte) ((l >> 24) & 0xFF),
                (byte) ((l >> 16) & 0xFF),
                (byte) ((l >> 8) & 0xFF),
                (byte) (l & 0xFF)
        };
    }

    public static byte[] longToByteArray16(Long l) {
        return new byte[]{
                (byte) ((l >> 56) & 0xFF),
                (byte) ((l >> 48) & 0xFF),
                (byte) ((l >> 40) & 0xFF),
                (byte) ((l >> 32) & 0xFF),
                (byte) ((l >> 24) & 0xFF),
                (byte) ((l >> 16) & 0xFF),
                (byte) ((l >> 8) & 0xFF),
                (byte) (l & 0xFF)
        };
    }


    public static void main(String[] args) {
//        String s="AE23C4D23E08CA7D34D53B1E";
//        byte[] bytes = hex2byte(s);

//        System.out.println(s1);
//        byte[] bytes = longToByteArray16(202312270001L);
//        System.out.println(byte2hex(bytes));
//        String s="hello word";
//        String hexStr = asciiToHex(s);
//        byte[] bytes = hex2byte(hexStr);
//        String rHexStr = byte2hex(bytes);
//        String ascii = hexToAscii(hexStr);
//        System.out.println(ascii);
//       String content = "E1FD1F5E09D1CE4226E8633C51CB87F9D4B3FC9CD0CF944440FA16F8C172E137A8E9023F4F318D091D06FA9A3E1E04C0C9272BDDB81100C46DEC6863FF52D2E152A733F2CEBF66609E2EF1881674901C";
//        String key = "Z4T6U7RL08VJ5Y36";
//        byte[] decrypt = decrypt(hex2byte(content), key);
//        log.info(new String(decrypt,StandardCharsets.UTF_8));

//
//        String str = "000200220000001800026048915E604888AD0000000000003039AE23C4D23E08CA7D34D53B1E";
//        byte[] crc2 = CrcUtil.getCrc(hex2byte(str));
//        String crcStr = byte2hex(crc2);
//        log.info("crc验证码:" + crcStr);
//        String sendData = str + crcStr;
//        log.info("发送数据:" + sendData);
//
//        String channelNoStr = getChannelNoStr(101L);
//        byte[] channelBytes = channelNoStr.getBytes(StandardCharsets.UTF_8);
//        log.info("渠道号:" + channelNoStr);
//        long l = Long.parseLong(channelNoStr, 16);
//        log.info("渠道号:" + l);
//
//
//        byte[] encrypt = encrypt(alignByte(sendData), key);
//        log.info("加密数据:" + byte2hex(encrypt));
//
//        byte[] finalSendData = createFinalSendData(encrypt, channelBytes);
//        log.info("最终发送数据:" + new String(finalSendData, StandardCharsets.UTF_8));
//
//        byte[] finalGetData = getFinalGetData(finalSendData);
//        log.info("收到数据:" + byte2hex(finalGetData));
//
//        byte[] decryptArr = decrypt(finalGetData, key);
//        byte[] decrypt = removeTrailingZeroBytes(decryptArr);
//        log.info("解密数据:" + new String(decrypt, StandardCharsets.UTF_8));
//
//        if (!checkCrc(decrypt)) return;
//
//        int version = getVersion(decrypt);
//        log.info("数据版本:" + version);
//
//        int len = getDataLenth(decrypt);
//        log.info("数据长度:" + len);
//
//        int serializeNumber = getSerializeNumber(decrypt);
//        log.info("数据序列号:" + serializeNumber);
//
//        String typeStr = getTypeStr(decrypt);
//        log.info("数据类型:" + typeStr);
//
//        LocalDateTime sendTime = getSendTime(decrypt, 20, 28);
//        log.info("数据发送时间:" + sendTime.format(DateTimeFormatter.ISO_DATE_TIME));
//
//        LocalDateTime occurTime = getOccurTime(decrypt);
//        log.info("数据发生时间:" + occurTime.format(DateTimeFormatter.ISO_DATE_TIME));
//
//        Long deviceNumber = getDeviceNumber(decrypt);
//        log.info("设备编号:" + deviceNumber);
//
//        String deviceSerializeNumber = getDeviceSerializeNumber(decrypt);
//        log.info("设备序列号:" + deviceSerializeNumber);


    }

    public static byte[] getFinalGetData(byte[] finalSendData) {
        int len = finalSendData.length - PROTOCOL_PREFIX.length - 4 - PROTOCOL_SUFFIX.length;//4是渠道长度
        byte[] finalGetData = new byte[len];
        System.arraycopy(finalSendData, PROTOCOL_PREFIX.length + 4, finalGetData, 0, len);
        //要进行转换一次
        return hex2byte(new String(finalGetData, StandardCharsets.UTF_8));
    }


    public static byte[] createFinalSendData(byte[] encrypt, byte[] channelBytes) {

        String encryptStr = byte2hex(encrypt);
        byte[] crcBytes = createCrcStr(new String(channelBytes)+encryptStr).getBytes(StandardCharsets.UTF_8);
        byte[] encryptBytes = encryptStr.getBytes(StandardCharsets.UTF_8);

        int secondLength = PROTOCOL_PREFIX.length + channelBytes.length;
        int threeLength = secondLength + encryptBytes.length;
        int fourLength = threeLength + crcBytes.length;
        int totalLength = fourLength + PROTOCOL_SUFFIX.length;


        byte[] finalSendData = new byte[totalLength];
        System.arraycopy(PROTOCOL_PREFIX, 0, finalSendData, 0, PROTOCOL_PREFIX.length);
//        log.info("头:"+new String(finalSendData, StandardCharsets.UTF_8));

        System.arraycopy(channelBytes, 0, finalSendData, PROTOCOL_PREFIX.length, channelBytes.length);
//        log.info("渠道:"+new String(finalSendData, StandardCharsets.UTF_8));

        System.arraycopy(encryptBytes, 0, finalSendData, secondLength, encryptBytes.length);
//        log.info("加密数据"+new String(finalSendData, StandardCharsets.UTF_8));

        System.arraycopy(crcBytes, 0, finalSendData, threeLength, crcBytes.length);

        System.arraycopy(PROTOCOL_SUFFIX, 0, finalSendData, fourLength, PROTOCOL_SUFFIX.length);
        return finalSendData;
    }

    public static String getChannelNoStr(Long channelNo) {
        String hexString = Long.toHexString(channelNo);
        int i = 4 - hexString.length();
        if (i > 0) {
            for (int j = 0; j < i; j++) {
                hexString = "0" + hexString;
            }
        }
        return hexString;
    }

    public static boolean checkCrc(byte[] decrypt) {
        String decryptStr = new String(decrypt, StandardCharsets.UTF_8);
//        log.info("解密后数据:{}", decryptStr);

        byte[] valueData = new byte[decrypt.length - 4];
        System.arraycopy(decrypt, 0, valueData, 0, decrypt.length - 4);
//        log.info("crc数据:{}", new String(valueData, StandardCharsets.UTF_8));

        String deviceCrcStr = getCrcStr(decrypt);
//        log.info("deviceCrcStr:" + deviceCrcStr);

        byte[] crc = CrcUtil.getCrc(Objects.requireNonNull(hex2byte(new String(valueData, StandardCharsets.UTF_8))));
        String crcNew = byte2hex(crc);
//        log.info("校验crc:" + crcNew);

        if (deviceCrcStr.equals(crcNew)) {
//            log.info("crc校验通过");
            return true;
        }
//        log.info("crc校验不通过");
        return false;
    }

    //获取数据长度
    public static int getDataLenth(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 4, 8);
        return byteArrayToLong(lenArr).intValue();
    }

    //获取数据版本
    public static int getVersion(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 0, 4);
        return byteArrayToLong(lenArr).intValue();
    }

    //获取数据序列号
    public static int getSerializeNumber(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 8, 16);
        return byteArrayToLong(lenArr).intValue();
    }

    //获取数据类型
    public static String getTypeStr(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 16, 20);
        return "0x" + byteArrayToLong(lenArr);
    }

    //获取发送时间戳
    public static LocalDateTime getSendTime(byte[] decrypt, int from, int to) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, from, to);
        log.info("发送时间字符串:{}", new String(lenArr, StandardCharsets.UTF_8));
        return getLocalDateTimeByBytes(lenArr);
    }

    public static LocalDateTime getLocalDateTimeByBytes(byte[] lenArr) {
        Long i = byteArrayToLong(lenArr);
        Instant instant = Instant.ofEpochSecond(i);
        ZoneId zoneId = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zoneId);
    }

    //获取发送时间戳
    public static LocalDateTime getOccurTime(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 28, 36);
        return getLocalDateTimeByBytes(lenArr);
    }

    //获取设备编号
    public static Long getDeviceNumber(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 36, 52);
        return byteArrayToLong(lenArr);
    }


    //获取设备序列号
    public static String getDeviceSerializeNumber(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, 52, 76);

        return new String(lenArr, StandardCharsets.UTF_8);
    }

    //获取crc字符串
    public static String getCrcStr(byte[] decrypt) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, decrypt.length - 4, decrypt.length);

        return new String(lenArr, StandardCharsets.UTF_8);
    }

    //去除渠道号
    public static byte[] getNoChannelBytes(byte[] encryptData) {
        byte[] bytes = new byte[encryptData.length - 2];
        System.arraycopy(encryptData, 2, bytes, 0, bytes.length);
        return bytes;
    }

    //创建crcStr
    public static String createCrcStr(String sb) {
        byte[] bytes = TcpAesUtil.hex2byte(sb);
        byte[] crc = CrcUtil.getCrc(bytes);
        String crcStr = TcpAesUtil.byte2hex(crc);
        return crcStr;
    }



    //ascii转hex字符串
    public static String asciiToHex(String asciiStr) {
        StringBuilder hexStr = new StringBuilder();
        for (char ch : asciiStr.toCharArray()) {
            hexStr.append(Integer.toHexString((int) ch));
        }
        return hexStr.toString();
    }

    //hex字符串转ascii
    public static String hexToAscii(String hex) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hex.length() - 1; i += 2) {
            String h = hex.substring(i, (i + 2));
            int decimal = Integer.parseInt(h, 16);
            sb.append((char) decimal);
        }
        return sb.toString();
    }

    public static Long getByteToLong(byte[] bytes,int from,int to){
        byte[] lenArr = Arrays.copyOfRange(bytes, from, to);
        return byteArrayToLong(lenArr);
    }

    public static String getByteToString(byte[] decrypt,int from,int to) {
        byte[] lenArr = Arrays.copyOfRange(decrypt, from, to);

        return new String(lenArr, StandardCharsets.UTF_8);
    }
}
